import asyncio
import datetime
import logging
import shutil
import time

import requests
from fastapi import FastAPI, BackgroundTasks
from starlette.staticfiles import StaticFiles
from starlette.responses import Response
from starlette.types import Scope
from concurrent.futures import ThreadPoolExecutor
from api.request import FileDownloadRequest, CalculationRequest
from api.response import ApiResponse
from tools.HttpTools import post_json
from tools.LoggerTools import *
setup_global_logging()
from image_calculation_v2 import *



class CustomStaticFiles(StaticFiles):
    async def get_response(self, path: str, scope: Scope) -> Response:
        response = await super().get_response(path, scope)
        # 为所有静态文件添加header
        response.headers["Content-Disposition"] = "inline"
        return response


app = FastAPI(docs_url=None, redoc_url=None)
app.mount(
    "/static",
    StaticFiles(directory="static"),  # 注意这里只有一个右括号
    name="static",

)

file_dir_root = './files/'


def download_file(url, save_path):
    try:
        response = requests.get(url, stream=True)
        response.raise_for_status()  # 检查请求是否成功

        with open(save_path, 'wb') as file:
            for chunk in response.iter_content(chunk_size=8192):
                file.write(chunk)
        logging.info(f"文件已保存至: {save_path}")

    except requests.exceptions.RequestException as e:
        logging.info(f"下载失败: {e}")

def process_file_sync(file_download_request: FileDownloadRequest):
    try:
        now = datetime.datetime.now()
        time_str = now.strftime("%Y%m%d%H%M%S")
        # time_str = "20250825103118"
        file_path = file_dir_root + time_str
        logging.info(f"开始处理文件: {file_path}")
        os.makedirs(file_path, exist_ok=True)
        if (file_download_request.rbgimg_tif_url
                and file_download_request.realland_tif_url) :
            logging.info(f"开始下载tif文件")
            tis_path = file_path+"/tif/"
            os.makedirs(tis_path, exist_ok=True)
            download_file(file_download_request.rbgimg_tif_url, tis_path+'/rgbimg.tif')
            download_file(file_download_request.realland_tif_url, tis_path+'/realland.tif')
            logging.info(f"下载tif文件完成")
        if file_download_request.first_file_urls:
            logging.info(f"开始下载first_file文件")
            first_file_path = file_path+"/first_file/"
            os.makedirs(first_file_path, exist_ok=True)
            for idx,url in enumerate(file_download_request.first_file_urls):
                download_file(url, first_file_path+'/'+str(idx)+'.las')
            logging.info(f"下载first file文件完成")
        if file_download_request.second_file_urls:
            logging.info(f"开始下载second_file文件")
            second_file_path = file_path+"/second_file/"
            os.makedirs(second_file_path, exist_ok=True)
            for idx,url in enumerate(file_download_request.second_file_urls):
                download_file(url, second_file_path+'/'+str(idx)+'.las')
            logging.info(f"下载second_file文件完成")
        calculation(file_path,file_download_request)
        logging.info(f"处理文件完成")
        # delete_file(file_path)
    except  Exception as e:
        logging.error(f"处理文件出错: {e}")

def delete_file(file_path):
    if os.path.exists(file_path):
        shutil.rmtree(file_path)
        print(f"已清空文件夹：{file_path}")
    else:
        print(f"文件夹不存在：{file_path}")


# 调整参数
denose_nb_neighbors = 80  # 噪声的相邻要素数
denose_std_ratio = 0.5     # 噪声去除的标准偏差比率
api_url = "http://10.10.206.107:12001/ExternalApi/ExternalAiUavData/SaveWarningData"

def calculation(file_path,file_download_request: FileDownloadRequest):
    resolution = file_download_request.resolution
    threshold = file_download_request.threshold

    logging.info(f"开始进行计算 file_path = {file_path}")
    tif_file_dir = file_path + '/tif/'
    las_files_time1, las_files_time2, rgb_images_path, realland_images_path = get_all_files(file_path)
    gx1, gy1, gz1 = get_files_points(las_files_time1, resolution)
    gx2, gy2, gz2 = get_files_points(las_files_time2, resolution)
    gx3, gy3, gz_diff = dem_diff_overlap(gx1, gy1, gz1, gx2, gy2, gz2)

    logging.info(f'第一时间DEM: {gz1.shape}, {gx1[0][0]}, {gy1[0][0]}, {gx1[-1][-1]}, {gy1[-1][-1]}')
    logging.info(f'第二时间DEM: {gz2.shape}, {gx2[0][0]}, {gy2[0][0]},{ gx2[-1][-1]}, {gy2[-1][-1]}')
    logging.info(f'重叠高程差: {gz_diff.shape}, {gx3[0][0]}, {gy3[0][0]}, {gx3[-1][-1]}, {gy3[-1][-1]}')

    # 只保留超过threshold的高程差（下塌）
    threshold_mask = gz_diff >= threshold

    gz_diff_filtered = np.full_like(gz_diff, np.nan, dtype=float)
    gz_diff_filtered[threshold_mask] = gz_diff[threshold_mask]

    ratio = np.count_nonzero(threshold_mask) / threshold_mask.size
    logging.info(f"过滤后保留超过 {threshold:.2f} m 阈值的点占比：{ratio:.2%}")

    # 过滤掉排队图层中透明部分
    rows_m, cols_m, xs_m, ys_m, dz_m = filter_by_realland_mask(
        gx3, gy3, gz_diff_filtered, realland_images_path
    )

    # 在底图上叠加下塌点
    blue_img, x_top_left, y_top_left, x_right_bottom, y_right_bottom = overlay_blue_on_rgb(xs_m, ys_m, rgb_images_path)

    marked, infos, center_pix = mark_color_blocks_with_number_2(
        blue_img,
        target_rgb=(0, 0, 255), tol=10,
        min_area=500, max_area=15000,
        outline_color=(255, 0, 0), outline_width=2,
        text_color=(0, 255, 0), font_size=30,
        center_dist_thresh=10
    )

    # 保存图像
    marked_pic = f'static/marked_{file_download_request.task_id}.png'

    # resize图片
    image_resize = img_resize(marked)
    image_resize.save(marked_pic)

    logging.info(f"完成红框标记，已保存 {image_resize}")
    logging.info("检测到的框信息：")
    logging.info(f"底图左上角坐标: {x_top_left}, {y_top_left}, 右下角坐标: {x_right_bottom}, {y_right_bottom}")

    # 初始化结果列表
    result = {
        "Rightxy": [  # 可以根据需要补充底图的左上角和右下角坐标
            [x_top_left, y_top_left],
            [x_right_bottom, y_right_bottom]
        ],
        "LatAndLngList": []
    }

    # 计算图像的宽度和高度（地理坐标系）
    image_width = x_right_bottom - x_top_left
    image_height = y_right_bottom - y_top_left

    for item in infos:
        # 从归一化坐标（0-1范围）转换为实际地理坐标
        topleft_lon = x_top_left + item['topleft'][0] * image_width
        topleft_lat = y_top_left + item['topleft'][1] * image_height
        bottomright_lon = x_top_left + item['bottomright'][0] * image_width
        bottomright_lat = y_top_left + item['bottomright'][1] * image_height

        # 计算中心点坐标（左上角和右下角的平均值）
        center_lon = (topleft_lon + bottomright_lon) / 2
        center_lat = (topleft_lat + bottomright_lat) / 2

        # 构造单个坐标对象
        coordinate_obj = {
            "Index": item['index'],  # 序号
            "Center": [center_lon, center_lat],  # 中心点坐标
            "Topleft": [topleft_lon, topleft_lat],  # 左上角坐标
            "Bottomright": [bottomright_lon, bottomright_lat]  # 右下角坐标
        }
        # 添加到结果列表
        result["LatAndLngList"].append(coordinate_obj)

    json_request = {
        "TaskId" : file_download_request.task_id,
        "ImageUrl" : f'http://117.89.29.135:9876/' + marked_pic,
        "Rightxy" : result["Rightxy"],
        "LatAndLnglist" : result["LatAndLngList"]
    }

    try:
        logging.info("接口请求参数: %s",json_request)
        headers = {"ApiKey": "qdB5iXRcgJIiGfLmHqK2taosRqsuld"}
        response = post_json(api_url,json_request,headers=headers)
        # 输出响应结果
        logging.info(f"状态码: {response.status_code}")
        logging.info("响应内容:")
        logging.info(response.json())  # 如果响应是 JSON 格式
    except Exception as e:
        logging.error(f"请求接口出错",str(e))




# 创建全局线程池执行器
executor = ThreadPoolExecutor(max_workers=5)

async def run_in_thread(func, *args):
    """在单独线程中运行同步函数"""
    loop = asyncio.get_event_loop()
    return await loop.run_in_executor(executor, func, *args)


@app.post("/image_calculation",          summary="图片坐标计算",
          response_description="图片坐标计算"
          )
async def image_calculation(file_download_request: FileDownloadRequest,background_tasks: BackgroundTasks):
    logging.info(f"接口请求参数: {file_download_request}")

    # 将处理任务添加到后台
    background_tasks.add_task(run_in_thread,process_file_sync,file_download_request)

    return ApiResponse.success(None)
